iT邦幫忙

0

Java筆記:觀念釐清-stack及heap的差異

  • 分享至 

  • xImage
  •  

本篇為記錄不同的Java資料型態在記憶體中的變化情形,參考JVM 的 Stack 和 Heap並重點摘要。

Java語言中,資料型別分為基本型別參考(類別)型別2種,特性如下:

基本型別:byteshortintlongfloatdoublebooleanchar

特性

  1. 長度及生命週期都為可知 (程式碼區塊執行完變成GG)。
  2. 運算速度快,但長度與內容受限。

類別型態(或稱參考型態):Class Type ( Reference Type)

不屬於基本型別的,都屬於此類別,這種類型通常都需要用 new 去創建,如 User user = new User("Mark"); 。
特性

  1. 因為是在執行時才會創建,所以長度及生命週期都不可預知。
  2. 靈活但運算較耗時。

https://ithelp.ithome.com.tw/upload/images/20220123/20143762O0RZ7YLC0a.png

stack:

  1. 用來儲存函數路徑區域變數
  2. Primitive Type,在 Stack 內的變數值為實際值,如上圖變數a123
  3. 函數路徑:Stack 內的變數值為物件實體在 Heap 中回傳所在的記憶體位址,如上圖的0x1234。
  4. 後進先出 (FILO) 的容器,具有存取速度快和管理簡單的特點。
  5. 堆疊順序:先宣告的變數,值在最下面,由下往上堆,如圖b在a上面。
  6. 因為所存放的資料生命週期都是規律的(區域變數只能存在methods中),所以由系統自行去產生和回收空間即可,不用特別設計垃圾回收機制。

heap:

  1. Heap 內找一塊區域放置物件實體屬性資料,如圖中的name :Mark,並產生位址:0x1234
  2. 在 Heap 創建完成後才會回傳所在的記憶體位址stack
  3. 如果在類別中宣告的實體變數,沒有立即給值的情況下,也是要等new一個該類別的物件實體,才會在heap中建立該物件的值,並把預設值存放進去,之後再把記憶體位址stack
  4. 存放的是共享資料,所以同 Process 底下的其他 Thread 也可以進行存取。
  5. JAVA針對heap有 Garbage Collection 機制,因為無法掌握物件實體的生命週期,所以存取速度慢,但是GC是否有提升效能的部分還是有待討論。


延伸:

兩個物件實體:當a物件 = b物件,代表b物件在stack中只是把heap的位址給a物件。
兩個區域變數:a = b,代表區域變數b在stack中把區域變數a的值給覆蓋
運作如下圖

https://ithelp.ithome.com.tw/upload/images/20220126/20143762L2gsP6M9J6.png

當在heap中沒被參考到的物件,也就是沒有變數儲存他的位址(如上圖0x12),就由JVM的GC機制回收並釋放記憶體空間。


當方法的參數使用基本型別跟類別型別的差異:

	static void passValue(double value) {
		value = 20.0;
	}
	
	static void passReference(Pen reference) {
		reference.price = 20.0;
	}
	
	public static void main(String[] args) {
		double price = 10.0;
		passValue(price);
		System.out.println(price);        // 10
		
		Pen myPen = new Pen();
		myPen.price = 10.0;
		passReference(myPen);
		System.out.println(myPen.price);  // 20
	}

解:
當資料為基本型別時:

  1. 在stack會建立price 值為10.0的空間。
  2. 當方法passValue調用該值成為該方法的參數時,會在stack再建立一個空間儲存該參數(value)的值10.0
  3. 在方法裡面的區域變數value被賦予新的值20.0
  4. 方法passValue運作結束,區域變數value的生命週期也結束了。
  5. main方法的price還是一樣沒有變化為10.0

當資料為類別型別時:

  1. 在heap會建立屬性price 值為10.0的空間,並回傳位址0x12給stack並儲存在變數myPen
  2. 當方法passReference調用該值(位址0x12)成為該方法的參數時,會在stack再建立一個空間儲存該參數(reference)的值0x12
  3. 在方法裡面的區域變數reference的屬性price 值在heap中會被更改為20.0
  4. 方法passReference運作結束,區域變數reference的生命週期也結束了。
  5. main方法的myPen因為屬性price 的值在heap中已經被更改為20.0,所以最後print出來的值就變為20.0。

https://ithelp.ithome.com.tw/upload/images/20220126/20143762dP4SuIOn0r.png

參考資料:
JVM 的 Stack 和 Heap:https://blog.marklee.tw/java-interview-jvm-stack-heap/


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言